/*****************************************************************************/
/*                                                                           */
/*    Domino Operation System Kernel Module                                  */
/*                                                                           */
/*    Copyright (C) 2005-2013 Laszlo Arvai                                   */
/*                                                                           */
/*    ------------------------------------------------------------------   */
/*    String handler functions                                               */
/*****************************************************************************/
#include <string.h>
#include <ctype.h>
#include <krnlString.h>
#include <krnlAsciiCodes.h>

///////////////////////////////////////////////////////////////////////////////
// Local functions
static void strConversionAdjustBuffer( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength in_pos, dosStringLength in_field_length, dosByte in_options, dosStringLength in_buffer_index );

///////////////////////////////////////////////////////////////////////////////
// Get string length (in character)
dosStringLength strGetLength( dosString in_string )
{
	return (dosStringLength)strlen( (char*)in_string );
}

///////////////////////////////////////////////////////////////////////////////
// Get const string length (in character)
dosStringLength strGetConstLength( dosConstString in_string )
{
	return (dosStringLength)strlen( (char*)in_string );
}

///////////////////////////////////////////////////////////////////////////////
// Copy character to ram buffer
dosStringLength strCopyCharacter(dosString in_destination, dosStringLength in_destination_size, dosStringLength in_pos, dosChar in_char)
{
	if(in_pos < in_destination_size)
		in_destination[in_pos++] = in_char;

	if(in_pos < in_destination_size)
		in_destination[in_pos] = '\0';

	return in_pos;
}

///////////////////////////////////////////////////////////////////////////////
// Copy string to ram buffer
dosStringLength strCopyString( dosString in_destination, dosStringLength in_destination_size, dosStringLength in_destination_pos, dosString in_source )
{
	while(in_destination_pos < in_destination_size - 1 && *in_source != '\0')
	{
		in_destination[in_destination_pos++] = *in_source++;
	}

	in_destination[in_destination_pos] = '\0';

	return in_destination_pos;
}

///////////////////////////////////////////////////////////////////////////////
// Copy constant string to ram buffer
dosStringLength strCopyConstString( dosString in_destination, dosStringLength in_destination_size, dosStringLength in_destination_pos, 
													dosConstString in_source )
{
	// set position
	in_destination += in_destination_pos;
	
	while( *in_source != 0 && in_destination_pos < in_destination_size - 1)
	{
		*in_destination++ = *in_source++;
		in_destination_pos++;
	}
	
	*in_destination = '\0';

	return in_destination_pos;
}

///////////////////////////////////////////////////////////////////////////////
// Concat constant string to ram buffer
void strAppendConstString( dosString in_destination, dosStringLength in_destination_size, 
														dosConstString in_source )
{
	strCopyConstString( in_destination, in_destination_size, strGetLength( in_destination ), in_source );
}

///////////////////////////////////////////////////////////////////////////////
// Concat two string
void strAppendString( dosString in_destination, dosStringLength in_destination_size, dosString in_source )
{
	dosStringLength dest_pos = 0;
	dosStringLength source_pos = 0;

	// find end of the destination string
	while(in_destination[dest_pos] != '\0')
		dest_pos++;

	// copy string
	while(dest_pos < in_destination_size && in_source[source_pos] != '\0')
	{
		in_destination[dest_pos++] = in_source[source_pos++];
	}

	// close string
	if(dest_pos < in_destination_size)
		in_destination[dest_pos] = '\0';
	else
	{
		if(in_destination_size > 0 )
			in_destination[in_destination_size-1]  = '\0';
	}
}

///////////////////////////////////////////////////////////////////////////////
// Find character
dosInt16 strFindChar( dosString in_buffer, dosChar in_char )
{
	dosWord index = 0;
	
	while( *in_buffer != '\0' )
	{
		if( *in_buffer == in_char )
			return index;
			
		in_buffer++;
		index++;
	}
	
	return -1;
}

///////////////////////////////////////////////////////////////////////////////
// Set Length
void strSetLength( dosString in_destination, dosStringLength in_destination_size, dosChar in_char, dosStringLength in_required_length )
{
	dosStringLength length = strGetLength( in_destination );

	in_destination += length;	
	
	while( length < in_required_length && length < in_destination_size - 1 )
	{
		*in_destination++ = in_char;
		length++;
	}
	
	*in_destination = '\0';
}
	
///////////////////////////////////////////////////////////////////////////////
// Fill string buffer with a specified character
void strFillString( dosString in_destination, dosStringLength in_destination_size, dosChar in_char, dosStringLength in_start_pos, dosWord in_required_length )
{
	dosStringLength length;
	
	length = in_start_pos;
	in_destination += in_start_pos;
	
	while( length < in_required_length && length < in_destination_size - 1 )
	{
		*in_destination++ = in_char;
		length++;
	}
	
	*in_destination = '\0';
}


///////////////////////////////////////////////////////////////////////////////
// Convert from Unicode character to dosChar
dosASCIIChar strUnicodeToASCIIChar( dosWord in_unicode )
{
	if( in_unicode <= 0xff )
		return (dosChar)in_unicode;
	else
		return (dosChar)0xff;
}

///////////////////////////////////////////////////////////////////////////////
// Char To Upper
dosChar charToUpper( dosChar in_char )
{
	return toupper( in_char );
}

///////////////////////////////////////////////////////////////////////////////
// Char To Lower
dosChar charToLower( dosChar in_char )
{
	return tolower( in_char );
}

///////////////////////////////////////////////////////////////////////////////
// Int16 to string
void strAppendInt16ToString( dosString in_buffer, dosByte in_buffer_length, dosInt16 in_value, dosByte in_field_length, dosByte in_precision, dosByte in_options )
{
	dosWord value;
	dosStringLength pos;
	
	if( in_value < 0 )
	{
		value = (dosWord)(-in_value);
		in_options |= TS_DISPLAY_MINUS_SIGN;
	}
	else
	{
		value = (dosWord)in_value;
	}
	
	pos = strGetLength( in_buffer );
		
	strWordToStringPos( in_buffer, in_buffer_length, pos, value, in_field_length, in_precision, in_options );
}	

///////////////////////////////////////////////////////////////////////////////
// Int16 to string
void strInt16ToString( dosString in_buffer, dosByte in_buffer_length, dosInt16 in_value, dosByte in_field_length, dosByte in_precision, dosByte in_options )
{
	dosWord value;
	
	if( in_value < 0 )
	{
		value = (dosWord)(-in_value);
		in_options |= TS_DISPLAY_MINUS_SIGN;
	}
	else
	{
		value = (dosWord)in_value;
	}
		
	strWordToStringPos( in_buffer, in_buffer_length, 0, value, in_field_length, in_precision, in_options );
}

///////////////////////////////////////////////////////////////////////////////
// Word to string
dosStringLength strWordToString( dosString in_buffer, dosStringLength in_buffer_length, dosWord in_value, dosByte in_field_length, dosByte in_precision, dosByte in_options )
{
	return strWordToStringPos( in_buffer, in_buffer_length, 0, in_value, in_field_length, in_precision, in_options );
}	

///////////////////////////////////////////////////////////////////////////////
// Append word to string
dosStringLength strAppendWordToString( dosString in_buffer, dosStringLength in_buffer_length, dosWord in_value, dosByte in_field_length, dosByte in_precision, dosByte in_options )
{
	dosStringLength pos;
	
	pos = strGetLength( in_buffer );
		
	return strWordToStringPos( in_buffer, in_buffer_length, pos, in_value, in_field_length, in_precision, in_options );
}	

///////////////////////////////////////////////////////////////////////////////
// Word to string
dosStringLength strWordToStringPos( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength in_pos, dosWord in_value, dosByte in_field_length, dosByte in_precision, dosByte in_options )
{
	dosBool zero_blank = dosTrue;
	int divisor = 10000;
	dosByte digit_index = 5;
	dosByte digit;
	dosStringLength buffer_index = in_pos;
	dosStringLength field_length = in_buffer_length - in_pos - 1;
	
	// adjust length
	if( in_field_length != 0 && in_field_length < field_length )
		field_length = in_field_length;
	
	// parameter checking
	if( in_buffer_length - buffer_index <= 1 || in_buffer == NULL || field_length < 1 )
		return in_pos;
		
	if( (in_options & TS_DISPLAY_MINUS_SIGN) != 0 )
			in_buffer[buffer_index++] = '-';

	// send digits
	while( divisor > 0 && (buffer_index - in_pos) < field_length )
	{
		// store dot
		if( digit_index == in_precision )
		{
			if( zero_blank )
				in_buffer[buffer_index++] = '0';
				
			if( (buffer_index - in_pos) < field_length )
				in_buffer[buffer_index++] = '.';
			
			zero_blank = dosFalse;
		}

		// calculate digit
		digit = (dosByte)(in_value / divisor);
		
		// store digit
		if( (digit != 0 || !zero_blank || (divisor == 1) ||
				((in_options & TS_NO_ZERO_BLANKING) != 0 && digit_index <= field_length)) && ((buffer_index - in_pos) < field_length) )
		{
			in_buffer[buffer_index++] = digit + '0';
			zero_blank = dosFalse;
		}
	
		// calculate remaining
		in_value -= digit * divisor;
	
		// next digit
		digit_index--;
		divisor /= 10;
	}
	
	// if conversion was unsuccessfull
	if( divisor > 0 || buffer_index >= in_buffer_length - 1 )
	{
		strFillString( in_buffer, in_buffer_length, '#', in_pos, in_pos + field_length );
		buffer_index = field_length;
	}
	else
	{
		// adjust buffer
		if( in_field_length != 0 )
		{
			strConversionAdjustBuffer( in_buffer, in_buffer_length, in_pos, field_length, in_options, buffer_index );

			buffer_index = field_length + in_pos;
		}

		// terminate buffer
		in_buffer[buffer_index] = '\0';
	}

	return buffer_index;
}

///////////////////////////////////////////////////////////////////////////////
// Int32 to string
void strInt32ToString( dosString in_buffer, dosStringLength in_buffer_length, dosInt32 in_value, dosByte in_field_length, dosByte in_precision, dosByte in_options )
{
	strInt32ToStringPos( in_buffer, in_buffer_length, 0, in_value, in_field_length, in_precision, in_options );
}	

///////////////////////////////////////////////////////////////////////////////
// Int32 to string
void strAppendInt32ToString( dosString in_buffer, dosStringLength in_buffer_length, dosInt32 in_value, dosByte in_field_length, dosByte in_precision, dosByte in_options )
{
	dosStringLength pos;
	
	pos = strGetLength( in_buffer );

	strInt32ToStringPos( in_buffer, in_buffer_length, pos, in_value, in_field_length, in_precision, in_options );
}	
		

///////////////////////////////////////////////////////////////////////////////
// Int32 to string
dosStringLength strInt32ToStringPos( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength in_pos, dosInt32 in_value, dosByte in_field_length, dosByte in_precision, dosByte in_options )
{
	dosDWord value;
	
	if( in_value < 0 )
	{
		value = (dosDWord)(-in_value);
		in_options |= TS_DISPLAY_MINUS_SIGN;
	}
	else
	{
		value = (dosDWord)in_value;
	}
		
	return strDWordToStringPos( in_buffer, in_buffer_length, in_pos, value, in_field_length, in_precision, in_options );
}

///////////////////////////////////////////////////////////////////////////////
// DWord to string
void strDWordToString( dosString in_buffer, dosStringLength in_buffer_length, dosDWord in_value, dosByte in_field_length, dosByte in_precision, dosByte in_options )
{
	strDWordToStringPos( in_buffer, in_buffer_length, 0, in_value, in_field_length, in_precision, in_options );
}	

///////////////////////////////////////////////////////////////////////////////
// DWord to string pos
dosStringLength strDWordToStringPos( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength in_pos, dosDWord in_value, dosByte in_field_length, dosByte in_precision, dosByte in_options )
{
	dosBool zero_blank = dosTrue;
	dosDWord divisor = 1000000000ul;
	dosByte digit_index = 10;
	dosByte digit;
	dosStringLength buffer_index = in_pos;
	dosStringLength field_length = in_buffer_length - in_pos - 1;
	
	// adjust length
	if( in_field_length != 0 && in_field_length < field_length )
		field_length = in_field_length;
	
	// parameter checking
	if( in_buffer_length - buffer_index <= 1 || in_buffer == NULL || field_length < 1 )
		return in_pos;

	if( (in_options & TS_DISPLAY_MINUS_SIGN) != 0 )
			in_buffer[buffer_index++] = '-';

	// send digits
	while( divisor > 0 && (buffer_index - in_pos) < field_length )
	{
		// store dot
		if( digit_index == in_precision )
		{
			if( zero_blank )
				in_buffer[buffer_index++] = '0';
				
			if( (buffer_index - in_pos) < field_length )
				in_buffer[buffer_index++] = '.';
			
			zero_blank = dosFalse;
		}

		// calculate digit
		digit = (dosByte)(in_value / divisor);
		
		// store digit
		if( (digit != 0 || !zero_blank || (divisor == 1) ||
				((in_options & TS_NO_ZERO_BLANKING) != 0 && digit_index <= field_length)) && ((buffer_index - in_pos) < field_length) )
		{
			in_buffer[buffer_index++] = digit + '0';
			zero_blank = dosFalse;
		}
	
		// calculate remaining
		in_value -= digit * divisor;
	
		// next digit
		digit_index--;
		divisor /= 10;
	}
	
	// if conversion was unsuccessfull
	if( divisor > 0 || buffer_index >= in_buffer_length - 1 )
	{
		strFillString( in_buffer, in_buffer_length, '#', in_pos, in_pos + field_length );
	}
	else
	{
		// adjust buffer
		if( in_field_length != 0 )
		{
			strConversionAdjustBuffer( in_buffer, in_buffer_length, in_pos, field_length, in_options, buffer_index );

			buffer_index = field_length + in_pos;
		}


		// terminate buffer
		in_buffer[buffer_index] = '\0';
	}

	return buffer_index;
}

///////////////////////////////////////////////////////////////////////////////
// Adjust buffer
static void strConversionAdjustBuffer( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength in_pos, dosStringLength in_field_length, dosByte in_options, dosStringLength in_buffer_index )
{
	dosStringLength digit_index;
	
	// right adjustment
	if( (in_options & TS_RIGHT_ADJUSTMENT) != 0 )
	{
		// adjust buffer to the right
		for( digit_index = 1; digit_index <= in_buffer_index - in_pos; digit_index++ )
			in_buffer[in_pos + in_field_length - digit_index] = in_buffer[in_buffer_index - digit_index];
			
		// fill begining of buffer
		for( digit_index = in_pos; digit_index < (in_pos + in_field_length) - in_buffer_index + in_pos; digit_index++ )
			in_buffer[digit_index] = ' ';
	}
	else
	{
		while( in_buffer_index < (in_field_length + in_pos) )
			in_buffer[in_buffer_index++] = ' ';
	}
}

///////////////////////////////////////////////////////////////////////////////
//! Converts Nibble to hex digit (uppercase)
//! \param Nibble to convert (0-15)
//! \return ASCII code of the converted HEX character ('0'-'F')
dosChar strNibbleToHexDigit( dosByte in_nibble )
{
	if( in_nibble > 9 )
		return in_nibble - 10 + 'A';
	else
		return in_nibble + '0';
}	

///////////////////////////////////////////////////////////////////////////////
// Word to hex string pos
dosStringLength strWordToHexStringPos( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength in_pos, dosWord in_value )
{
	if( in_pos + 5 < in_buffer_length )
	{
		in_buffer[in_pos++] = strNibbleToHexDigit( (in_value >> 12) & 0x0f );
		in_buffer[in_pos++] = strNibbleToHexDigit( (in_value >> 8) & 0x0f );
		in_buffer[in_pos++] = strNibbleToHexDigit( (in_value >> 4) & 0x0f );
		in_buffer[in_pos++] = strNibbleToHexDigit( in_value & 0x0f );
		in_buffer[in_pos] = '\0';
	}	

	return in_pos;
}	

///////////////////////////////////////////////////////////////////////////////
//! Converts DWord (32bit unsigned int) value to hex string and stores it at the given position
//! \param Buffer to store conversion result
//! \param Length of the buffer
//! \param Start position of the stored string
//! \param Value to convert
dosStringLength strDWordToHexStringPos( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength in_pos, dosDWord in_value )
{
	dosStringLength pos = in_pos;

	pos = strWordToHexStringPos(in_buffer, in_buffer_length, pos, (dosWord)(in_value >> 16));
	pos = strWordToHexStringPos(in_buffer, in_buffer_length, pos, (dosWord)(in_value & 0xffff));

	return pos;
}	

///////////////////////////////////////////////////////////////////////////////
// Word to hex string
void strWordToHexString( dosString in_buffer, dosStringLength in_buffer_length, dosWord in_value )
{
	strWordToHexStringPos( in_buffer, in_buffer_length, 0, in_value );
}	

///////////////////////////////////////////////////////////////////////////////
// Append Word to hex string
void strAppendWordToHexString( dosString in_buffer, dosStringLength in_buffer_length, dosWord in_value )
{
	dosStringLength pos;
	
	pos = strGetLength( in_buffer );

	strWordToHexStringPos( in_buffer, in_buffer_length, pos, in_value );
}	
 
///////////////////////////////////////////////////////////////////////////////
//! Converts byte value to hex string and stores it at the given position
//! \param Buffer to store conversion result
//! \param Length of the buffer
//! \param Start position of the stored string
//! \param Value to convert
void strByteToHexStringPos( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength in_pos, dosWord in_value )
{
	if( in_pos + 3 < in_buffer_length )
	{
		in_buffer[in_pos++] = strNibbleToHexDigit( (in_value >> 4) & 0x0f );
		in_buffer[in_pos++] = strNibbleToHexDigit( in_value & 0x0f );
		in_buffer[in_pos] = '\0';
	}	
}	

///////////////////////////////////////////////////////////////////////////////
//! Converts byte value to hex string
//! \param Buffer to store conversion result
//! \param Length of the buffer
//! \param Value to convert
void strByteToHexString( dosString in_buffer, dosStringLength in_buffer_length, dosWord in_value )
{
	strByteToHexStringPos( in_buffer, in_buffer_length, 0, in_value );
}	

///////////////////////////////////////////////////////////////////////////////
//! Converts byte value to hex string	and appends the result string to the end
//! of the given string buffer
//! \param Buffer to store conversion result
//! \param Length of the buffer
//! \param Value to convert
void strAppendByteToHexString( dosString in_buffer, dosStringLength in_buffer_length, dosWord in_value )
{
	dosStringLength pos;
	
	pos = strGetLength( in_buffer );

	strByteToHexStringPos( in_buffer, in_buffer_length, pos, in_value );
}	

/*****************************************************************************/
/* Comparision routines                                                      */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
//! Compares string with constant string
//! \param String to comapare
//! \param Constant string to compare
//! \return -1, 0, 1 depending of the result
int strCompareConstString(dosString in_string1, dosConstString in_string2)
{
  for( ;  *in_string1 == *in_string2; in_string1++, in_string2++)
	{
		if(*in_string1 == '\0')
			return 0;
	}
  return ((*(unsigned char *)in_string1 < *(unsigned char *)in_string2) ? -1 : +1);
}

///////////////////////////////////////////////////////////////////////////////
//! Compares string with constant string without case senitivity
//! \param String to comapare
//! \param Constant string to compare
//! \return -1, 0, 1 depending of the result
int strCompareConstStringNoCase(dosString in_string1, dosConstString in_string2)
{
	for( ;  charToUpper(*in_string1) == charToUpper(*in_string2); in_string1++, in_string2++)
	{
		if(*in_string1 == '\0')
			return 0;
	}
	return ((charToUpper(*in_string1) < charToUpper(*in_string2)) ? -1 : +1);
}

///////////////////////////////////////////////////////////////////////////////
//! Compares two strings
//! \param String1 to comapare
//! \param String2 to compare
//! \return -1, 0, 1 depending of the result
int strCompareString(dosString in_string1, dosString in_string2)
{
  for( ; *in_string1 == *in_string2; in_string1++, in_string2++)
	{
		if(*in_string1 == '\0')
			return 0;
	}
  return ((*(unsigned char *)in_string1 < *(unsigned char *)in_string2) ? -1 : +1);
}

///////////////////////////////////////////////////////////////////////////////
//! Compares two strings without case sensitivity
//! \param String1 to comapare
//! \param String2 to compare
//! \return -1, 0, 1 depending of the result
int strCompareStringNoCase(dosString in_string1, dosString in_string2)
{
  for( ; charToUpper(*in_string1) == charToUpper(*in_string2); in_string1++, in_string2++)
	{
		if(*in_string1 == '\0')
			return 0;
	}
  return (charToUpper(*in_string1) < charToUpper(*in_string2) ? -1 : +1);
}

/*****************************************************************************/
/* Parser routines                                                           */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
//! Skips whitespace characters (space, tab)
//! \param Buffer containing the string
//! \param Length of the buffer
//! \param Pointer to the character position variable (it wil be updated to point to the first non-whitespce character)
void strSkipWhitespaces(dosString in_string, dosStringLength in_buffer_length, dosStringLength* in_index)
{
	while( *in_index < in_buffer_length && (in_string[*in_index] == ' ' || in_string[*in_index] == ASCII_HT) )
		(*in_index)++;
}

///////////////////////////////////////////////////////////////////////////////
//! Skips to the end of the line
//! \param Buffer containing the string
//! \param Length of the buffer
//! \param Pointer to the character position variable (it wil be updated to point to the first character on the next line)
//! \param Line end type
void strSkipLineEnd(dosString in_string, dosStringLength in_buffer_length, dosStringLength* in_index, dosStringLineEnd in_line_end)
{
	dosStringLength pos = *in_index;

	switch (in_line_end)
	{
		// CR line end
		case dosString_LE_CR:
			while(pos < in_buffer_length && in_string[pos] != '\0' )
			{
				if( in_string[pos] == ASCII_CR)
				{
					pos++;
					break;
				}
				else
				{
					pos++;
				}
			}
			break;

		// LF line end
		case dosString_LE_LF:
			while(pos < in_buffer_length && in_string[pos] != '\0' )
			{
				if( in_string[pos] == ASCII_LF)
				{
					pos++;
					break;
				}
				else
				{
					pos++;
				}
			}
			break;

		// CRLF line end
		case dosString_LE_CRLF:
			while(pos < in_buffer_length - 1 && in_string[pos] != '\0' )
			{
				if( in_string[pos] == ASCII_CR && in_string[pos+1] == ASCII_LF )
				{
					pos += 2;
					break;
				}
				else
				{
					pos++;
				}
			}
			break;

		// LFCR line end
		case dosString_LE_LFCR:
			while(pos < in_buffer_length - 1 && in_string[pos] != '\0' )
			{
				if( in_string[pos] == ASCII_LF && in_string[pos+1] == ASCII_CR )
				{
					pos += 2;
					break;
				}
				else
				{
					pos++;
				}
			}
			break;
	}

	*in_index = pos;
}

///////////////////////////////////////////////////////////////////////////////
//! Checks for token
//! \param Buffer containing the string
//! \param Length of the buffer
//! \param Pointer to the character position variable (it wil be updated to point to the first character on the next line)
//! \param Pointer to the result status code variable (true - success, false - failed)
//! \param List of the expected tokens (terminated with null pointer)
//! \return Token index if token found or -1 if token was not found
int strCheckForTokenNoCase(dosString in_buffer, dosStringLength in_buffer_length, dosStringLength* inout_index, dosBool* in_success, dosConstString in_expected_tokens[])
{
	int token_index;
	dosStringLength token_pos;
	dosStringLength index;

	// sanity check
	if(!(*in_success) || *inout_index >= in_buffer_length || in_expected_tokens[0] == DOS_NULL)
		return -1;

	// search for token
	token_index = 0;
	while(token_index >= 0)
	{
		index = *inout_index;
		token_pos = 0;
		while( index < in_buffer_length && in_buffer[index] != '\0' && in_expected_tokens[token_index][token_pos] != '\0')
		{
			if( charToUpper( in_buffer[index++] ) != charToUpper( in_expected_tokens[token_index][token_pos++]) )
				break;
		}

		if(in_expected_tokens[token_index][token_pos] == '\0')
		{
			// found
			*inout_index = index;
			break;
		}
		else
		{
			// not found
			token_index++;
			if(in_expected_tokens[token_index] == DOS_NULL)
			{
				*in_success = dosFalse;
				token_index = -1;
			}
		}
	}

	return token_index;
}

///////////////////////////////////////////////////////////////////////////////
// Check for const string (ignore case)
void strCheckForConstStringNoCase(dosString in_buffer, dosStringLength in_buffer_length, dosStringLength* inout_index, dosBool* in_success, dosConstString in_string )
{
	dosBool success = dosTrue;
	dosStringLength index = *inout_index;
	
	if(!(*in_success))
		return;

	while( index < in_buffer_length && in_buffer[index] != '\0' && *in_string != '\0' && *in_success )
	{
		if( charToUpper( in_buffer[index] ) != charToUpper( *in_string ) )
			*in_success = dosFalse;
			
		index++;
		in_string++;
	}
	
	if( index == *inout_index || *in_string != '\0' )
		*in_success = dosFalse;

	if( success )
		*inout_index = index;
}

///////////////////////////////////////////////////////////////////////////////
// Check for const string
void strCheckForConstString(dosString in_buffer, dosStringLength in_buffer_length, dosStringLength* inout_index, dosBool* in_success, dosConstString in_string )
{
	dosBool success = dosTrue;
	dosStringLength index = *inout_index;

	if(!(*in_success))
		return;

	while( index < in_buffer_length && in_buffer[index] != '\0' && *in_string != '\0' && *in_success )
	{
		if( in_buffer[index] != *in_string )
			*in_success = dosFalse;

		index++;
		in_string++;
	}

	if( index == *inout_index || *in_string != '\0' )
		*in_success = dosFalse;

	if( success )
		*inout_index = index;
}

///////////////////////////////////////////////////////////////////////////////
//! Checks for const char (e.g. separator)
//! \param Buffer containing the string
//! \param Length of the buffer
//! \param Pointer to the character position variable (it wil be updated to point to the first character on the next line)
//! \param Pointer to the result status code variable (true - success, false - failed)
//! \param Expected character
void strCheckForSeparator( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength* in_index, dosBool* in_success, dosChar in_char )
{
	if( *in_index < in_buffer_length && *in_success && in_buffer[*in_index] == in_char )
	{
		(*in_index)++;
	}
	else
		*in_success = dosFalse;	
}

///////////////////////////////////////////////////////////////////////////////
// String to dosByte
void strStringToByte( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength* in_index, dosBool* in_success, dosByte* out_number )
{
	dosWord number;
	
	// convert to word
	strStringToWord( in_buffer, in_buffer_length, in_index, in_success, &number );
	
	// check for overflow
	if( number > DOSBYTE_MAX )
		*in_success = dosFalse;
		
	// store result
	*out_number = (dosByte)number;
}	

///////////////////////////////////////////////////////////////////////////////
// String to dosInt16 conversion
void strStringToInt16( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength* in_index, dosBool* in_success, dosInt16* out_number )
{
	dosBool neg = dosFalse;
	dosWord number;

	// return if success flag is false
	if( !(*in_success) )
		return;

	// check for '-' sign
	if( in_buffer[*in_index] == '-' )
	{
		(*in_index)++;
		neg = dosTrue;
	}

	// convert
	strStringToWord( in_buffer, in_buffer_length, in_index, in_success, &number );

	// check for overflow
	if( neg )
	{
		if( number > -DOSINT16_MIN )
			*in_success = dosFalse;
	}
	else
	{
		if( number > DOSINT16_MAX )
			*in_success = dosFalse;
	}	
	
	if( *in_success )
		*out_number = number;
	
	// add sign
	if( *in_success && neg )
		*out_number = -(*out_number);
}	

///////////////////////////////////////////////////////////////////////////////
// String to dosWord conversion
void strStringToWord( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength* in_index, dosBool* in_success, dosWord* out_number )
{
	dosByte digits = 0;
	dosByte dig;

	// initialize
	*out_number = 0;
	
	if( !(*in_success) || in_buffer == DOS_NULL || in_buffer_length == 0)
		return;

	// convert char to int	
	while( in_buffer[*in_index] >= '0' && in_buffer[*in_index] <= '9' && *in_success)
	{
		// get digit
		dig = in_buffer[*in_index] - '0';
		
		// check for overflow and add digit to number
		if(*out_number < 6553 || (*out_number == 6553 && digits <= 5 ) )
			*out_number = *out_number * 10 + dig;
		else
			*in_success = dosFalse; // overflow error

		(*in_index)++;

		digits++;
	}

	if( digits == 0 )
		*in_success = dosFalse;
}

///////////////////////////////////////////////////////////////////////////////
// String to int (16bit) general conversion
void strStringToFixedInt16( dosString in_buffer, dosStringLength* in_index, dosBool* in_success, dosInt16* out_number, dosByte in_fixed_point, dosWord in_divisor )
{
	dosBool neg = dosFalse;
	dosWord number;
	
	// initialize
	*out_number = 0;
	number = 0;
	
	if( !(*in_success) )
		return;
		
	// check for '-' sign
	if( in_buffer[*in_index] == '-' )
	{
		(*in_index)++;
		neg = dosTrue;
	}

	// convert to word	
	strStringToFixedWord( in_buffer, in_index, in_success, &number, in_fixed_point, in_divisor );

	// check for overflow
	if( *in_success )
	{
		if( neg )
		{
			if( number > -DOSINT16_MIN )
				*in_success = dosFalse;
		}
		else
		{
			if( number > DOSINT16_MAX )
				*in_success = dosFalse;
		}	
	}
		
	// convert to fixed point
	if( *in_success )
	{
		// add sign
		if( neg )
			*out_number = -number;
		else
			*out_number = number;
	}
}

///////////////////////////////////////////////////////////////////////////////
// String to int (16bit) general conversion
void strStringToFixedWord( dosString in_buffer, dosStringLength* in_index, dosBool* in_success, dosWord* out_number, dosByte in_fixed_point, dosWord in_divisor )
{
	dosByte digits;
	dosByte dig;
	dosByte dot_pos = 0xff;
	dosWord number;
	dosWord power_of_fixed;
	
	// initialize
	*out_number = 0;
	number = 0;
	
	if( !(*in_success) )
		return;
		
	// calculate 10^in_fixed_point
	power_of_fixed = 1;
	
	for( digits = 0; digits < in_fixed_point; digits++ )
		power_of_fixed *= 10;
		
	// convert char to int
	digits = 0;	
	while( (in_buffer[*in_index] == '.' || (in_buffer[*in_index] >= '0' && in_buffer[*in_index] <= '9')) && *in_success)
	{
		// check for dot
		if( in_buffer[*in_index] == '.' )
		{
			// if this is the first dot store position
			if( dot_pos == 0xff )
			{
				dot_pos = digits;
			}
			else
			{
				// second dot -> error
				*in_success = dosFalse;
			}	
		}
		else
		{
			if( (dot_pos == 0xff) || (digits - dot_pos < in_fixed_point) )
			{
				// get digit
				dig = in_buffer[*in_index] - '0';
				
				// check for overflow and add digit to number
				if(number < 6553 || (number == 6553 && dig <= 5 ) )
					number = number * 10 + dig;
				else
					*in_success = dosFalse; // overflow error
		
				digits++;
			}
		}
		
		// next character
		(*in_index)++;
	}

	if( digits == 0 )
		*in_success = dosFalse;

	// convert to fixed point
	if( *in_success )
	{
		// if there was no dot
		if( dot_pos == 0xff )
			dot_pos = digits;
			
		// adjust missing fractions
		while( digits - dot_pos < in_fixed_point )
		{
			number *= 10;
			digits++;
		}	

		*out_number = (dosWord)(((dosDWord)number * in_divisor + (power_of_fixed/2-1)) / power_of_fixed);
	}
}

///////////////////////////////////////////////////////////////////////////////
// String to dosWord conversion
void strStringToDWord( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength* in_index, dosBool* in_success, dosDWord* out_number )
{
	dosByte digits = 0;
	dosByte dig;

	// sanity check
	if( !(*in_success) || in_buffer == DOS_NULL || in_buffer_length == 0)
	{
		*in_success = dosFalse;
		return;
	}

	// initialize
	*out_number = 0;

	// convert char to DWord	
	while( in_buffer[*in_index] >= '0' && in_buffer[*in_index] <= '9' && *in_success)
	{
		// get digit
		dig = in_buffer[*in_index] - '0';
		
		// check for overflow and add digit to number
		if(*out_number < 429496729 || (*out_number == 429496729 && dig <= 6 ) )
			*out_number = *out_number * 10 + dig;
		else
			*in_success = dosFalse; // overflow error

		(*in_index)++;

		digits++;
	}

	if( digits == 0 )
		*in_success = dosFalse;
}

///////////////////////////////////////////////////////////////////////////////
// String to int (32bit) general conversion
void strStringToFixedDWord( dosString in_buffer, dosStringLength* in_index, dosBool* in_success, dosDWord* out_number, dosByte in_fixed_point, dosDWord in_divisor )
{
	dosByte digits;
	dosByte dig;
	dosByte dot_pos = 0xff;
	dosDWord number;
	dosDWord power_of_fixed;
	
	// initialize
	*out_number = 0;
	number = 0;
	
	if( !(*in_success) )
		return;
		
	// calculate 10^in_fixed_point
	power_of_fixed = 1;
	
	for( digits = 0; digits < in_fixed_point; digits++ )
		power_of_fixed *= 10;
		
	// convert char to int
	digits = 0;	
	while( (in_buffer[*in_index] == '.' || (in_buffer[*in_index] >= '0' && in_buffer[*in_index] <= '9')) && *in_success)
	{
		// check for dot
		if( in_buffer[*in_index] == '.' )
		{
			// if this is the first dot store position
			if( dot_pos == 0xff )
			{
				dot_pos = digits;
			}
			else
			{
				// second dot -> error
				*in_success = dosFalse;
			}	
		}
		else
		{
			if( (dot_pos == 0xff) || (digits - dot_pos < in_fixed_point) )
			{
				// get digit
				dig = in_buffer[*in_index] - '0';
				
				// check for overflow and add digit to number
				if(number < 429496729 || (number == 429496729 && dig <= 6 ) )
					number = number * 10 + dig;
				else
					*in_success = dosFalse; // overflow error
		
				digits++;
			}
		}
		
		// next character
		(*in_index)++;
	}

	if( digits == 0 )
		*in_success = dosFalse;

	// convert to fixed point
	if( *in_success )
	{
		// if there was no dot
		if( dot_pos == 0xff )
			dot_pos = digits;
			
		// adjust missing fractions
		while( digits - dot_pos < in_fixed_point )
		{
			number *= 10;
			digits++;
		}	

		*out_number = (dosDWord)(((dosUInt64)number * in_divisor + (power_of_fixed/2-1)) / power_of_fixed);
	}
}

///////////////////////////////////////////////////////////////////////////////
// Hex digit to nibble
dosByte strHexDigitToNibble( dosChar in_digit, dosBool* in_success )
{
	if( *in_success )
	{
		if( charIsDigit(in_digit) )
			return in_digit - '0';
		else
		{
			if( in_digit >= 'A' && in_digit <= 'F' )
				return in_digit - 'A' + 10;
			else
			{
				if( in_digit >= 'a' && in_digit <= 'f' )
					return in_digit - 'a' + 10;
				else
					*in_success = dosFalse;
			}	
		}	
	}	
	
	return 0;
}	

///////////////////////////////////////////////////////////////////////////////
// Hex string to word
void strHexStringToWord( dosString in_buffer, dosStringLength* in_index, dosBool* in_success, dosWord* out_number )
{
	dosByte digits;

	// init
	*out_number = 0;

	// convert characters
	digits = 0;	
	while( charIsHexDigit(in_buffer[*in_index]) && in_success && digits < 4)
	{
		*out_number = ((*out_number) << 4) + strHexDigitToNibble( in_buffer[(*in_index)++], in_success );
		digits++;
	}
}	

///////////////////////////////////////////////////////////////////////////////
//! Converts hex string to DWord (32-bit unsigned)
//! \param Buffer containing the string
//! \param Length of the buffer
//! \param Pointer to the character position of the hex value
//! \param Pointer to the result status code variable (true - success, false - failed)
//! \param Output value
void strHexStringToDWord( dosString in_buffer, dosStringLength in_buffer_length, dosStringLength* in_index, dosBool* in_success, dosDWord* out_number )
{
	dosByte digits;

	// sanity check
	if( !(*in_success) || in_buffer == DOS_NULL || in_buffer_length == 0)
	{
		*in_success = dosFalse;
		return;
	}

	// init
	*out_number = 0;

	// convert characters
	digits = 0;	
	while( charIsHexDigit(in_buffer[*in_index]) && in_success && digits < 8)
	{
		*out_number = ((*out_number) << 4) + strHexDigitToNibble( in_buffer[(*in_index)++], in_success );
		digits++;
	}
}
